/**
 * API请求封装
 * 统一处理请求、响应和错误
 */

const config = require('./config.js');

// 不需要登录就可以访问的公共API列表
const PUBLIC_APIS = [
  config.API.CATEGORY.LIST,
  config.API.CATEGORY.DETAIL,
  config.API.CATEGORY.PRODUCTS,
  config.API.HOME.BANNER,
  config.API.PRODUCT.RECOMMEND,
  config.API.PRODUCT.DETAIL,
  config.API.PRODUCT.LIST
];

// 判断是否是公共API
function isPublicApi(url) {
  return PUBLIC_APIS.some(api => {
    // 判断是否以某个公共API为前缀，支持带ID的路径，如detail/1
    return url.startsWith(api) || 
           // 如果API以/结尾，则需要移除/再比较
           (api.endsWith('/') && url.startsWith(api.substring(0, api.length - 1)));
  });
}

/**
 * 统一请求函数
 * @param {String} url 请求地址
 * @param {Object} data 请求参数
 * @param {String} method 请求方法
 * @param {Boolean} loading 是否显示loading
 * @returns {Promise}
 */
function request(url, data = {}, method = 'GET', loading = true) {
  // 完整的请求地址
  const fullUrl = `${config.API_BASE_URL}${url}`;
  
  // 打印详细的请求信息，便于调试
  console.log(`[API请求] ${method} ${fullUrl}`, data);
  console.log(`请求参数:`, data);
  
  // 是否显示loading
  if (loading) {
    wx.showLoading({
      title: '加载中...',
      mask: true
    });
  }
  
  // 获取token
  const token = wx.getStorageSync('token');
  console.log(`当前token:`, token);
  
  // 请求头
  const header = {
    'Content-Type': 'application/json'
  };
  
  // 检查是否是公共API
  const isPublic = isPublicApi(url);
  console.log(`API ${url} 是否为公共API:`, isPublic);
  
  // 如果不是公共API且有token，则添加token到请求头
  if (!isPublic && token) {
    header['Authorization'] = `Bearer ${token}`;
    console.log(`已添加Authorization头:`, header.Authorization);
  } else if (!isPublic && !token) {
    // 如果不是公共API且没有token，记录日志
    console.warn(`请求非公共API但无token: ${url}`);
  }
  
  return new Promise((resolve, reject) => {
    // 设置请求超时
    const timeoutMs = 15000; // 15秒超时
    let timeout = false;
    
    // 创建超时计时器
    const timer = setTimeout(() => {
      timeout = true;
      if (loading) {
        wx.hideLoading();
      }
      
      console.error('[API请求]请求超时:', fullUrl);
      
      // 显示超时提示（可选）
      wx.showToast({
        title: '网络请求超时',
        icon: 'none',
        duration: 2000
      });
      
      reject({ errMsg: 'request:timeout', statusCode: 408 });
    }, timeoutMs);
    
    wx.request({
      url: fullUrl,
      data: data,
      method: method,
      header: header,
      // 添加以下配置，防止微信小程序自动编码中文字符
      enableHttp2: true,
      enableQuic: true,
      enableCache: true,
      success: function(res) {
        // 清除超时定时器
        clearTimeout(timer);
        if (timeout) return; // 如果已经超时，不处理
        
        if (loading) {
          wx.hideLoading();
        }
        
        // 打印详细的响应信息，便于调试
        console.log(`[API响应] ${method} ${fullUrl}`, res);
        
        // 判断请求是否成功
        if (res.statusCode === 200 || res.statusCode === 201) {
          // 业务状态码判断
          if (res.data.code && res.data.code !== 200 && res.data.code !== 0 && res.data.code !== 201) {
            // 401: 未登录
            if (res.data.code === 401) {
              console.log('[API响应] 未登录错误，需要登录', res.data);
              wx.showToast({
                title: '请先登录',
                icon: 'none'
              });
              
              // 清除可能无效的token
              wx.removeStorageSync('token');
              
              // 可以在这里跳转到登录页
              setTimeout(() => {
                wx.navigateTo({
                  url: '/pages/my/index'
                });
              }, 1500);
            } else {
              // 其他业务错误
              console.log('[API响应] 业务错误', res.data);
              wx.showToast({
                title: res.data.message || '请求失败',
                icon: 'none'
              });
            }
            reject(res.data);
          } else {
            // 请求成功
            if (res.statusCode === 201) {
              console.log('[API响应] 创建成功 201', res.data);
            }
            resolve(res.data);
          }
        } else {
          // HTTP错误
          console.log('[API响应] HTTP错误', res);
          wx.showToast({
            title: `请求失败: ${res.statusCode}`,
            icon: 'none'
          });
          reject(res);
        }
      },
      fail: function(err) {
        // 清除超时定时器
        clearTimeout(timer);
        if (timeout) return; // 如果已经超时，不处理
        
        if (loading) {
          wx.hideLoading();
        }
        console.error('[API请求]失败', err);
        console.error('[API请求]失败详情:', {
          url: fullUrl,
          method: method,
          errorMsg: err.errMsg,
          errno: err.errno
        });
        
        // 根据错误类型提供更具体的提示
        let errorMsg = '网络请求失败';
        if (err.errMsg) {
          if (err.errMsg.includes('timeout')) {
            errorMsg = '请求超时，请检查网络';
          } else if (err.errMsg.includes('fail')) {
            errorMsg = '网络连接失败，请检查网络设置';
          }
        }
        
        // 连接被拒绝时，显示友好提示
        if (err.errMsg && err.errMsg.includes('CONNECTION_REFUSED')) {
          errorMsg = '服务器暂时不可用，请稍后再试';
          console.error('[API请求]连接被拒绝，服务器可能未启动');
        }
        
        // 避免大量重复的错误提示，影响用户体验
        // 选择性地显示错误信息
        const showErrorToast = !url.includes('/orders/recent'); // 对于订单接口不显示toast
        
        if (showErrorToast) {
          wx.showToast({
            title: errorMsg,
            icon: 'none'
          });
        }
        
        reject(err);
      }
    });
  });
}

/**
 * GET请求
 * @param {String} url 请求地址
 * @param {Object} data 请求参数
 * @param {Boolean} loading 是否显示loading
 * @returns {Promise}
 */
function get(url, data = {}, loading = true) {
  return request(url, data, 'GET', loading);
}

/**
 * POST请求
 * @param {String} url 请求地址
 * @param {Object} data 请求参数
 * @param {Boolean} loading 是否显示loading
 * @returns {Promise}
 */
function post(url, data = {}, loading = true) {
  return request(url, data, 'POST', loading);
}

/**
 * PUT请求
 * @param {String} url 请求地址
 * @param {Object} data 请求参数
 * @param {Boolean} loading 是否显示loading
 * @returns {Promise}
 */
function put(url, data = {}, loading = true) {
  return request(url, data, 'PUT', loading);
}

/**
 * DELETE请求
 * @param {String} url 请求地址
 * @param {Object} data 请求参数
 * @param {Boolean} loading 是否显示loading
 * @returns {Promise}
 */
function del(url, data = {}, loading = true) {
  return request(url, data, 'DELETE', loading);
}

// 导出API方法
module.exports = {
  get,
  post,
  put,
  delete: del
}; 